C++/C#: Reuse unaliased SSA when building aliased SSA#3235
Closed
dbartol wants to merge 1 commit into
Closed
Conversation
We build SSA twice. The first iteration, "unaliased SSA", considers only those memory locations that are not aliased, do not have their address escape, and are always accessed in their entirety and as their underlying declared type. The second iteration, "aliased SSA", considers all memory locations. However, since whatever defs and uses we computed for unaliased SSA are still valid for aliased SSA, because they never overlap with the aliased memory locations that aliased SSA adds into the mix. If we can reuse the unaliased SSA information directly, we can potentially save significant cost in building aliased SSA. The main changes in this PR are in `SSAConstruction.qll`. Instead of throwing away all `Phi` instructions from the previous IR iteration, we bring them along. When computing the definition for a given use, if that use already had a definition in the previous iteration, we reuse that definition. This is slightly complicated by the possibility of degenerate (single-operand) `Phi` instructions due to unreachable code being eliminated between iterations. If we would have wound up with a degenerate `Phi` instruction, we recurse to the definition of that `Phi` instruction's sole reachable input operand. See the new test cases for a couple examples. In aliased SSA's `AliasConfiguration.qll`, I stopped creating allocations for variables that were already modeled in unaliased SSA. This in turn prevents us from creating memory locations for those variables and their defs and uses, which is where we hope to reduce evaluation time. I also tweaked the `getInstructionUniqueId()` predicate to reuse the unique ID from the previous stage, which preserves ordering of `Phi` instructions in a block to minimize test output diffs. The `points_to` test had to be updated to no longer expect points-to analysis on unaliased SSA to report results that were already reported when running on raw IR. Finally, I added `PhiInstruction.getInputOperand()`. I'm surprised we didn't have it already.
MathiasVP
reviewed
Apr 9, 2020
| tag = oldOperand.getOperandTag() and | ||
| ( | ||
| ( | ||
| not instruction instanceof UnmodeledUseInstruction and |
Contributor
There was a problem hiding this comment.
I'm curious as to why we didn't need this condition before? Or is it you having to tell the optimizer that one instruction cannot satisfy both disjunctions after changing the predicate?
rdmarsh2
reviewed
Apr 9, 2020
| ) | ||
| } | ||
|
|
||
| private predicate willResultBeModeled(OldInstruction oldInstruction) { |
Contributor
There was a problem hiding this comment.
I found this name confusing, partly because it reads as a question rather than an assertion, partly because it seems like it could mean will it ever be modeled rather than will this stage model it.
jbj
reviewed
Apr 14, 2020
Comment on lines
+169
to
+178
| if | ||
| phiOperandOverlap instanceof MustExactlyOverlap and | ||
| originalOverlap instanceof MustExactlyOverlap | ||
| then overlap instanceof MustExactlyOverlap | ||
| else | ||
| // Pedantically, multiple levels of `MustTotallyOverlap` could combine to yield a | ||
| // `MustExactlyOverlap`. We won't worry about that because unaliased SSA always produces | ||
| // exact overlap, and even if it did not, `MustTotallyOverlap` is a valid conservative | ||
| // approximation. | ||
| overlap instanceof MustTotallyOverlap |
Contributor
There was a problem hiding this comment.
A helper predicate would read better.
Comment on lines
+42
to
+45
| unique(OldIR::PhiInputOperand operand | | ||
| operand = oldInstruction.(OldIR::PhiInstruction).getAnInputOperand() and | ||
| operand.getPredecessorBlock() instanceof OldBlock | ||
| ) |
Contributor
There was a problem hiding this comment.
We need to get the green light to use unique.
Author
|
Superceded by #3340 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Leaving this PR as a draft until I have perf measurements from real snapshots to validate the expected speedup
We build SSA twice. The first iteration, "unaliased SSA", considers only those memory locations that are not aliased, do not have their address escape, and are always accessed in their entirety and as their underlying declared type. The second iteration, "aliased SSA", considers all memory locations. However, since whatever defs and uses we computed for unaliased SSA are still valid for aliased SSA, because they never overlap with the aliased memory locations that aliased SSA adds into the mix. If we can reuse the unaliased SSA information directly, we can potentially save significant cost in building aliased SSA.
The main changes in this PR are in
SSAConstruction.qll. Instead of throwing away allPhiinstructions from the previous IR iteration, we bring them along. When computing the definition for a given use, if that use already had a definition in the previous iteration, we reuse that definition. This is slightly complicated by the possibility of degenerate (single-operand)Phiinstructions due to unreachable code being eliminated between iterations. If we would have wound up with a degeneratePhiinstruction, we recurse to the definition of thatPhiinstruction's sole reachable input operand. See the new test cases for a couple examples.In aliased SSA's
AliasConfiguration.qll, I stopped creating allocations for variables that were already modeled in unaliased SSA. This in turn prevents us from creating memory locations for those variables and their defs and uses, which is where we hope to reduce evaluation time.I also tweaked the
getInstructionUniqueId()predicate to reuse the unique ID from the previous stage, which preserves ordering ofPhiinstructions in a block to minimize test output diffs.The
points_totest had to be updated to no longer expect points-to analysis on unaliased SSA to report results that were already reported when running on raw IR.Finally, I added
PhiInstruction.getInputOperand(). I'm surprised we didn't have it already.